package com.naiterui.ehp.bs.file.api.handler;

import java.util.Collections;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;

import com.naiterui.ehp.bp.support.utils.IpUtil;
import com.naiterui.ehp.bp.utils.lang.ConfigUtil;
import com.naiterui.ehp.bs.file.api.annotation.SafeUrlMappingTransfer;
import com.naiterui.ehp.bs.file.api.bo.FileBO;
import com.naiterui.ehp.bs.file.api.bo.FileHeaderBO;
import com.naiterui.ehp.bs.file.api.bo.FileParamBO;
import com.naiterui.ehp.bs.file.api.exception.FileException;
import com.naiterui.ehp.bs.file.api.feign.FileFeignClient;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.json.JSONUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * 文件安全处理
 * 
 * @author luao
 * @date 2022/1/5 4:57 下午
 **/
@Slf4j
@Component
@RequiredArgsConstructor
public class FileSafeHandler {

    private final FileFeignClient fileFeignClient;

    private static final String imgHost = ConfigUtil.getString("ehp.domain.img");
    private static final String fileHost = ConfigUtil.getString("ehp.domain.fileHost");

    private final Pattern PATTERN_IMG = Pattern.compile(genRegex(imgHost, "\\\"", true));
    private final Pattern PATTERN_FILE = Pattern.compile(genRegex(fileHost, "\\\"", true));

    /**
     * 安全url转换为文件真实路径
     * 
     * @param t
     * @param <T>
     * @return
     */
    public <T> T prepareRealUrl(T t) {
        if (t == null) {
            return t;
        }
        // 针对单个url的情况
        if (t instanceof String) {
            return (T)prepareRealUrl((String)t);
        }
        // 针对实体类情况
        String json = JSONUtil.toJsonStr(t);
        Matcher matcher = PATTERN_FILE.matcher(json);
        Set<String> filePathSet = CollectionUtil.newHashSet();
        while (matcher.find()) {
            String filePath = matcher.group();
            filePathSet.add(filePath);
        }
        if (CollectionUtil.isEmpty(filePathSet)) {
            return t;
        }

        // 通过安全url批量获取文件信息
        Map<String, FileBO> fileMap;
        try {
            fileMap = fileFeignClient.batchRealPath(filePathSet);
        } catch (FileException e) {
            log.error("批量获取文件真实路径错误", e);
            fileMap = Collections.emptyMap();
        }

        // 替换文件真实路径
        StringBuffer sb = new StringBuffer();
        Matcher handlerMatcher = PATTERN_FILE.matcher(json);
        while (handlerMatcher.find()) {
            String filePath = handlerMatcher.group();
            FileBO fileBO = fileMap.getOrDefault(filePath, FileBO.builder().url("").build());
            handlerMatcher.appendReplacement(sb, fileBO.getUrl());
        }
        handlerMatcher.appendTail(sb);
        return (T)JSONUtil.toBean(sb.toString(), t.getClass());
    }

    private String prepareRealUrl(String str) {
        String res;
        try {
            res = fileFeignClient.getRealPath(str);
        } catch (FileException e) {
            log.error("获取文件真实路径错误", e);
            res = "";
        }
        return res;
    }

    /**
     * 安全URL生成
     *
     * @param responseStr
     *            响应原文
     * @return
     */
    public String prepareSafeUrl(String responseStr, SafeUrlMappingTransfer safeUrlTransfer,
        HttpServletRequest request) {
        String prefix = StringUtils.defaultIfBlank(safeUrlTransfer.customPrefix(), imgHost);
        boolean replace = safeUrlTransfer.customPrefixReplace();

        Pattern pathPattern =
            StringUtils.equals(imgHost, prefix) ? PATTERN_IMG : Pattern.compile(genRegex(prefix, "\\\"", true));

        Matcher matcher = pathPattern.matcher(responseStr);
        Set<String> filePathSet = CollectionUtil.newHashSet();
        while (matcher.find()) {
            String filePath = matcher.group();
            filePathSet.add(replace ? filePath.replace(prefix, "") : filePath);
        }
        // 调用API处理
        Map<String, FileBO> fileMap;
        try {
            fileMap =
                fileFeignClient
                    .batchGeneratePreview(FileParamBO.builder()
                        .fileHeader(FileHeaderBO.builder().ip(IpUtil.getIp(request))
                            .ua(request.getHeader(HttpHeaders.USER_AGENT))
                            .referer(request.getHeader(HttpHeaders.REFERER)).build())
                        .filePaths(ListUtil.toList(filePathSet)).timeLength(safeUrlTransfer.timeLength())
                        .timeCheck(safeUrlTransfer.timeCheck()).ipCheck(safeUrlTransfer.ipCheck())
                        .uaCheck(safeUrlTransfer.uaCheck()).refererCheck(safeUrlTransfer.refererCheck()).build());
        } catch (FileException e) {
            log.error("批量生成预览Url错误", e);
            fileMap = Collections.emptyMap();
        }
        Map<String, FileBO> finalFileMap = fileMap;
        Map<String, String> filePathMap = filePathSet.stream().collect(Collectors.toMap(Function.identity(),
            key -> Optional.ofNullable(finalFileMap.get(key)).map(FileBO::getUrl).orElse(key), (a, b) -> b));

        // 安全URL替换处理
        if (CollectionUtil.isEmpty(filePathMap)) {
            return responseStr;
        }
        StringBuffer sb = new StringBuffer();
        Matcher handlerMatcher = pathPattern.matcher(responseStr);
        while (handlerMatcher.find()) {
            String filePath = handlerMatcher.group();
            String imgUrl = filePathMap.getOrDefault(replace ? filePath.replace(prefix, "") : filePath, filePath);
            handlerMatcher.appendReplacement(sb, imgUrl);
        }
        handlerMatcher.appendTail(sb);
        return sb.toString();
    }

    /**
     * 简单正则规则生成
     *
     * @param start
     *            正则匹配前缀
     * @param end
     *            正则匹配后缀
     * @param isContain
     *            是否包含
     */
    public static String genRegex(String start, String end, boolean isContain) {
        String regex = null;
        if (isContain) {
            regex = "(?=(" + start + "))[.\\s\\S]*?(?=(" + end + "))";
        } else {
            regex = "(?<=(" + start + "))[.\\s\\S]*?(?=(" + end + "))";
        }
        return regex;
    }
}
